#include "PCIe_Switch.h"

PCIe_Switch::PCIe_Switch(sc_module_name		name_,
						 PCIe_id_t			id_,
						 PCIe_address_space	addr_SATA_mem_1_,
						 PCIe_address_space	addr_SATA_io_,
						 PCIe_address_space	addr_SATA_conf_,
						 PCIe_address_space	addr_SATA_mem_2_)
	: sc_module							(name_)
	, id								(id_)
	, DMI_port							(name_, SWITCH_ID, x4)
	, SATA_port							(name_, SATA_CONTROLLER_1_ID, x1)
	, DMI_current_state					(PL_IDLE)
	, SATA_current_state				(PL_IDLE)
	, DMI_sequence_number				(0)
	, DMI_NAK_free_sequence_number		(0)
	, SATA_sequence_number				(0)
	, SATA_NAK_sequence_number			(0)
	, SATA_NAK_free_sequence_number		(0)
	, DMI_stop							(false)
	, SATA_stop							(false)
	, DMI_buffer_DLL_TLP_down_in		(0)
	, DMI_buffer_DLL_TLP_down_out		(0)
	, DMI_buffer_DLL_TLP_down_time		(0,SC_NS)
	, DMI_buffer_DLL_TLP_up_in			(0)
	, DMI_buffer_DLL_TLP_up_out			(0)
	, DMI_buffer_DLL_TLP_up_ack_nak		(0)
	, DMI_buffer_DLL_TLP_up_time		(0,SC_NS)
	, SATA_buffer_DLL_TLP_down_in		(0)
	, SATA_buffer_DLL_TLP_down_out		(0)
	, SATA_buffer_DLL_TLP_down_ack_nak	(0)
	, SATA_buffer_DLL_TLP_down_time		(0,SC_NS)
	, SATA_buffer_DLL_TLP_up_in			(0)
	, SATA_buffer_DLL_TLP_up_out		(0)
	, SATA_buffer_DLL_TLP_up_time		(0,SC_NS)
	, DMI_buffer_TLP_down_in			(0)
	, DMI_buffer_TLP_down_out			(0)
	, DMI_buffer_TLP_down_time			(0,SC_NS)
	, DMI_buffer_TLP_up_in				(0)
	, DMI_buffer_TLP_up_out				(0)
	, DMI_buffer_TLP_up_time			(0,SC_NS)
	, SATA_buffer_TLP_down_in			(0)
	, SATA_buffer_TLP_down_out			(0)
	, SATA_buffer_TLP_down_time			(0,SC_NS)
	, SATA_buffer_TLP_up_in				(0)
	, SATA_buffer_TLP_up_out			(0)
	, SATA_buffer_TLP_up_time			(0,SC_NS)
	, DMI_buffer_DLLP_down_in			(0)
	, DMI_buffer_DLLP_down_out			(0)
	, DMI_buffer_DLLP_down_time			(0,SC_NS)
	, DMI_buffer_DLLP_up_in				(0)
	, DMI_buffer_DLLP_up_out			(0)
	, DMI_buffer_DLLP_up_time			(0,SC_NS)
	, SATA_buffer_DLLP_down_in			(0)
	, SATA_buffer_DLLP_down_out			(0)
	, SATA_buffer_DLLP_down_time		(0,SC_NS)
	, SATA_buffer_DLLP_up_in			(0)
	, SATA_buffer_DLLP_up_time			(0,SC_NS)
	, SATA_buffer_DLLP_up_out			(0)
	, DMI_DLL_TLP_seq_num_cnt			(1)
	, DMI_TLP_header_cnt				(0)
	, DMI_TLP_data_cnt					(0)
	, DMI_TLP_ECRC_cnt					(3)
	, DMI_DLL_TLP_LCRC_cnt				(3)
	, DMI_DLLP_data_cnt					(2)
	, DMI_DLLP_CRC_cnt					(1)
	, SATA_DLL_TLP_seq_num_cnt			(1)
	, SATA_TLP_header_cnt				(0)
	, SATA_TLP_data_cnt					(0)
	, SATA_TLP_ECRC_cnt					(3)
	, SATA_DLL_TLP_LCRC_cnt				(3)
	, SATA_DLLP_data_cnt				(0)
	, SATA_DLLP_CRC_cnt					(1)
	, DMI_granted_packet_type			(0)
	, SATA_granted_packet_type			(0)
{
	switch_address_map.push_back(addr_SATA_mem_1_);
	switch_address_map.push_back(addr_SATA_io_);
	switch_address_map.push_back(addr_SATA_conf_);
	switch_address_map.push_back(addr_SATA_mem_2_);

	SC_THREAD(DMI_switch_action);
	dont_initialize();
	sensitive << CLK.pos();

	SC_THREAD(SATA_switch_action);
	dont_initialize();
	sensitive << CLK.pos();

	SC_THREAD(DMI_make_action);
	dont_initialize();
	sensitive << CLK.pos();

	SC_THREAD(DMI_TLP_send_action);
	dont_initialize();
	sensitive << CLK.pos();

	SC_THREAD(SATA_make_action);
	dont_initialize();
	sensitive << CLK.pos();

	SC_THREAD(SATA_TLP_send_action);
	dont_initialize();
	sensitive << CLK.pos();

	SC_THREAD(DMI_ack_nak_action);
	dont_initialize();
	sensitive << CLK.pos();

	SC_THREAD(DMI_DLLP_send_action);
	dont_initialize();
	sensitive << CLK.pos();

	SC_THREAD(SATA_ack_nak_action);
	dont_initialize();
	sensitive << CLK.pos();

	SC_THREAD(SATA_DLLP_send_action);
	dont_initialize();
	sensitive << CLK.pos();
}

PCIe_Switch::~PCIe_Switch()
{
	for (int i=0; i<MAX_BUFFER_SWITCH; i++)
	{
		delete[] DMI_buffer_DLL_TLP_down[i].TLP.header;
		if (DMI_buffer_DLL_TLP_down[i].TLP.with_data)
			delete[] DMI_buffer_DLL_TLP_down[i].TLP.data;
		delete[] SATA_buffer_DLL_TLP_down[i].TLP.header;
		if (SATA_buffer_DLL_TLP_down[i].TLP.with_data)
			delete[] SATA_buffer_DLL_TLP_down[i].TLP.data;

		delete[] DMI_buffer_TLP_down[i].header;
		if (DMI_buffer_TLP_down[i].with_data)
			delete[] DMI_buffer_TLP_down[i].data;
		delete[] SATA_buffer_TLP_down[i].header;
		if (SATA_buffer_TLP_down[i].with_data)
			delete[] SATA_buffer_TLP_down[i].data;

		delete[] DMI_buffer_TLP_up[i].header;
		if (DMI_buffer_TLP_up[i].with_data)
			delete[] DMI_buffer_TLP_up[i].data;
		delete[] SATA_buffer_TLP_up[i].header;
		if (SATA_buffer_TLP_up[i].with_data)
			delete[] SATA_buffer_TLP_up[i].data;

		delete[] DMI_buffer_DLL_TLP_up[i].TLP.header;
		if (DMI_buffer_DLL_TLP_up[i].TLP.with_data)
			delete[] DMI_buffer_DLL_TLP_up[i].TLP.data;
		delete[] SATA_buffer_DLL_TLP_up[i].TLP.header;
		if (SATA_buffer_DLL_TLP_up[i].TLP.with_data)
			delete[] SATA_buffer_DLL_TLP_up[i].TLP.data;
	}
}

void
PCIe_Switch::PL_send_symbol(PCIe_id_t		id_,
							PCIe_symbol_t	symbol_)
{
	switch (symbol_)
	{
	case STP:
		if (id_ == DMI_port.get_id())
		{
			DMI_DLL_TLP_seq_num_cnt = 1;
			DMI_TLP_header_cnt = 0;
			DMI_TLP_data_cnt =	0;
			DMI_TLP_ECRC_cnt = 3;
			DMI_DLL_TLP_LCRC_cnt = 3;
			DMI_is_STP = true;
			DMI_current_state = TLP_SEQ_NUM;
		}
		else if (id_ == SATA_port.get_id())
		{
			SATA_DLL_TLP_seq_num_cnt = 1;
			SATA_TLP_header_cnt = 0;
			SATA_TLP_data_cnt =	0;
			SATA_TLP_ECRC_cnt = 3;
			SATA_DLL_TLP_LCRC_cnt = 3;
			SATA_is_STP = true;
			SATA_current_state = TLP_SEQ_NUM;
		}
		break;
	case SDP:
		if (id_ == DMI_port.get_id())
		{
			DMI_DLLP_data_cnt = 0;
			DMI_DLLP_CRC_cnt = 1;
			DMI_is_STP = false;
			DMI_current_state = DLLP_TYPE;
		}
		else if (id_ == SATA_port.get_id())
		{
			SATA_DLLP_data_cnt = 0;
			SATA_DLLP_CRC_cnt = 1;
			SATA_is_STP = false;
			SATA_current_state = DLLP_TYPE;
		}
		break;
	case END:
		if (id_ == DMI_port.get_id())
		{
			if (DMI_is_STP)
			{
#ifdef	DEBUG_SWITCH
				cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "DMI Port : TLP has been received." << endl;
				cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Sequence Number : " << hex << DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_in].sequence_number << dec << endl;
				cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "TLP Header : ";
				int limit;
				if (DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_in].TLP.DW4_header)
					limit = 16;
				else
					limit = 12;
				for (int i=0; i<limit ; i++)
				{
					cout.width(2);
					cout.fill('0');
					cout << hex << (unsigned)DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_in].TLP.header[i] << dec << " ";
				}
				cout << endl;
				if (DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_in].TLP.with_data)
				{
					cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "TLP Data : ";
					if (DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_in].TLP.length == 0)
					{
						for (int i=0; i<1024*PCIe_DOUBLE_WORD; i++)
						{
							cout.width(2);
							cout.fill('0');
							switch (i%4)
							{
							case 0:
								cout << hex << ((DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_in].TLP.data[i/4]>>24) & 0xFF) << dec << " ";
								break;
							case 1:
								cout << hex << ((DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_in].TLP.data[i/4]>>16) & 0xFF) << dec << " ";
								break;
							case 2:
								cout << hex << ((DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_in].TLP.data[i/4]>>8) & 0xFF) << dec << " ";
								break;
							case 3:
								cout << hex << (DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_in].TLP.data[i/4] & 0xFF) << dec << " | ";
								break;
							}
						}
					}
					else
					{
						for (int i=0; i<DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_in].TLP.length*PCIe_DOUBLE_WORD; i++)
						{
							cout.width(2);
							cout.fill('0');
							switch (i%4)
							{
							case 0:
								cout << hex << ((DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_in].TLP.data[i/4]>>24) & 0xFF) << dec << " ";
								break;
							case 1:
								cout << hex << ((DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_in].TLP.data[i/4]>>16) & 0xFF) << dec << " ";
								break;
							case 2:
								cout << hex << ((DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_in].TLP.data[i/4]>>8) & 0xFF) << dec << " ";
								break;
							case 3:
								cout << hex << (DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_in].TLP.data[i/4] & 0xFF) << dec << " | ";
								break;
							}
						}
					}
					cout << endl;
				}
				cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "TLP ECRC : " << hex << DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_in].TLP.ECRC << dec << endl;
				cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "LCRC : " << hex << DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_in].LCRC << dec << endl;
#endif
				unsigned short received_seq_num;
				received_seq_num = DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_in].sequence_number;
				if (((DMI_buffer_TLP_down_in+1)%MAX_BUFFER_SWITCH != DMI_buffer_TLP_down_out) && (DMI_NAK_free_sequence_number == received_seq_num))
				{
					DMI_is_NAK = false;
					DMI_NAK_free_sequence_number = (received_seq_num+1)%4096;
				}
				else
				{
					DMI_is_NAK = true;
				}
				DMI_buffer_DLL_TLP_down_in = (DMI_buffer_DLL_TLP_down_in+1)%MAX_BUFFER_SWITCH;
				DMI_buffer_DLL_TLP_down_time = sc_time_stamp();
			}
			else
			{
#ifdef	DEBUG_SWITCH
				cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "DLLP Type : ";
				cout.width(2);
				cout.fill('0');
				cout << hex << DMI_buffer_DLLP_down[DMI_buffer_DLLP_down_in].type << dec << endl;
				cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "DLLP Data : ";
				for (int i=0; i<3 ; i++)
				{
					cout.width(2);
					cout.fill('0');
					cout << hex << (unsigned)DMI_buffer_DLLP_down[DMI_buffer_DLLP_down_in].data[i] << dec << " ";
				}
				cout << endl;
				cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "DLLP CRC : " << hex << DMI_buffer_DLLP_down[DMI_buffer_DLLP_down_in].CRC << dec << endl;
#endif
				if (DMI_buffer_DLLP_down[DMI_buffer_DLLP_down_in].type == NAK)
				{
					unsigned short received_seq_num;
					received_seq_num = ((unsigned short)DMI_buffer_DLLP_down[DMI_buffer_DLLP_down_in].data[1])<<8 | (unsigned short)DMI_buffer_DLLP_down[DMI_buffer_DLLP_down_in].data[2];
					if (DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_ack_nak].sequence_number == received_seq_num)
					{
						DMI_buffer_DLL_TLP_up_out = DMI_buffer_DLL_TLP_up_ack_nak;
						DMI_NAK_sequence_number = received_seq_num;
						DMI_stop = true;
					}
					else
					{
						cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Fatal Buffer Error!" << endl << flush;
						sc_stop();
					}
				}
				else
				{
					delete[] DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_ack_nak].TLP.header;
					if (DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_ack_nak].TLP.with_data)
						delete[] DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_ack_nak].TLP.data;
					DMI_buffer_DLL_TLP_up_ack_nak = (DMI_buffer_DLL_TLP_up_ack_nak+1)%MAX_BUFFER_SWITCH;
				}
				DMI_buffer_DLLP_down_in = (DMI_buffer_DLLP_down_in+1)%MAX_BUFFER_SWITCH;
				DMI_buffer_DLLP_down_out = (DMI_buffer_DLLP_down_out+1)%MAX_BUFFER_SWITCH;
				DMI_buffer_DLLP_down_time = sc_time_stamp();
			}
			DMI_current_state = PL_IDLE;
		}
		else if (id_ == SATA_port.get_id())
		{
			if (SATA_is_STP)
			{
#ifdef	DEBUG_SWITCH
				cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "SATA Port : TLP has been received." << endl;
				cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Sequence Number : " << hex << SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_in].sequence_number << dec << endl;
				cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "TLP Header : ";
				int limit;
				if (SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_in].TLP.DW4_header)
					limit = 16;
				else
					limit = 12;
				for (int i=0; i<limit ; i++)
				{
					cout.width(2);
					cout.fill('0');
					cout << hex << (unsigned)SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_in].TLP.header[i] << dec << " ";
				}
				cout << endl;
				if (SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_in].TLP.with_data)
				{
					cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "TLP Data : ";
					if (SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_in].TLP.length == 0)
					{
						for (int i=0; i<1024*PCIe_DOUBLE_WORD; i++)
						{
							cout.width(2);
							cout.fill('0');
							switch (i%4)
							{
							case 0:
								cout << hex << ((SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_in].TLP.data[i/4]>>24) & 0xFF) << dec << " ";
								break;
							case 1:
								cout << hex << ((SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_in].TLP.data[i/4]>>16) & 0xFF) << dec << " ";
								break;
							case 2:
								cout << hex << ((SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_in].TLP.data[i/4]>>8) & 0xFF) << dec << " ";
								break;
							case 3:
								cout << hex << (SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_in].TLP.data[i/4] & 0xFF) << dec << " | ";
								break;
							}
						}
					}
					else
					{
						for (int i=0; i<SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_in].TLP.length*PCIe_DOUBLE_WORD; i++)
						{
							cout.width(2);
							cout.fill('0');
							switch (i%4)
							{
							case 0:
								cout << hex << ((SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_in].TLP.data[i/4]>>24) & 0xFF) << dec << " ";
								break;
							case 1:
								cout << hex << ((SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_in].TLP.data[i/4]>>16) & 0xFF) << dec << " ";
								break;
							case 2:
								cout << hex << ((SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_in].TLP.data[i/4]>>8) & 0xFF) << dec << " ";
								break;
							case 3:
								cout << hex << (SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_in].TLP.data[i/4] & 0xFF) << dec << " | ";
								break;
							}
						}
					}
					cout << endl;
				}
				cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "TLP ECRC : " << hex << SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_in].TLP.ECRC << dec << endl;
				cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "LCRC : " << hex << SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_in].LCRC << dec << endl;
#endif
				unsigned short received_seq_num;
				received_seq_num = SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_in].sequence_number;
				if (((SATA_buffer_TLP_up_in+1)%MAX_BUFFER_SWITCH != SATA_buffer_TLP_up_out) && (SATA_NAK_free_sequence_number == received_seq_num))
				{
					SATA_is_NAK = false;
					SATA_NAK_free_sequence_number = (received_seq_num+1)%4096;
				}
				else
				{
					SATA_is_NAK = true;
				}
				SATA_buffer_DLL_TLP_up_in = (SATA_buffer_DLL_TLP_up_in+1)%MAX_BUFFER_SWITCH;
				SATA_buffer_DLL_TLP_up_time = sc_time_stamp();
			}
			else
			{
#ifdef	DEBUG_SWITCH
				cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "DLLP Type : ";
				cout.width(2);
				cout.fill('0');
				cout << hex << SATA_buffer_DLLP_up[SATA_buffer_DLLP_up_in].type << dec << endl;
				cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "DLLP Data : ";
				for (int i=0; i<3 ; i++)
				{
					cout.width(2);
					cout.fill('0');
					cout << hex << (unsigned)SATA_buffer_DLLP_up[SATA_buffer_DLLP_up_in].data[i] << dec << " ";
				}
				cout << endl;
				cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "DLLP CRC : " << hex << SATA_buffer_DLLP_up[SATA_buffer_DLLP_up_in].CRC << dec << endl;
#endif
				if (SATA_buffer_DLLP_up[SATA_buffer_DLLP_up_in].type == NAK)
				{
					unsigned short received_seq_num;
					received_seq_num = ((unsigned short)SATA_buffer_DLLP_up[SATA_buffer_DLLP_up_in].data[1])<<8 | (unsigned short)SATA_buffer_DLLP_up[SATA_buffer_DLLP_up_in].data[2];
					if (SATA_buffer_DLL_TLP_down[SATA_buffer_DLL_TLP_down_ack_nak].sequence_number == received_seq_num)
					{
						SATA_buffer_DLL_TLP_down_out = SATA_buffer_DLL_TLP_down_ack_nak;
						SATA_NAK_sequence_number = received_seq_num;
						SATA_stop = true;
					}
					else
					{
						cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Fatal Buffer Error!" << endl << flush;
						sc_stop();
					}
				}
				else
				{
					delete[] SATA_buffer_DLL_TLP_down[SATA_buffer_DLL_TLP_down_ack_nak].TLP.header;
					if (SATA_buffer_DLL_TLP_down[SATA_buffer_DLL_TLP_down_ack_nak].TLP.with_data)
						delete[] SATA_buffer_DLL_TLP_down[SATA_buffer_DLL_TLP_down_ack_nak].TLP.data;
					SATA_buffer_DLL_TLP_down_ack_nak = (SATA_buffer_DLL_TLP_down_ack_nak+1)%MAX_BUFFER_SWITCH;
				}
				SATA_buffer_DLLP_up_in = (SATA_buffer_DLLP_up_in+1)%MAX_BUFFER_SWITCH;
				SATA_buffer_DLLP_up_out = (SATA_buffer_DLLP_up_out+1)%MAX_BUFFER_SWITCH;
				SATA_buffer_DLLP_up_time = sc_time_stamp();
			}
			SATA_current_state = PL_IDLE;
		}
		break;
	default :
		cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Unknown Symbol!" << endl << flush;
		sc_stop();
	}
}

const bool
PCIe_Switch::DLL_send_sequence_number_byte(PCIe_id_t	id_,
										   byte			seq_num_)
{
	if (id_ == DMI_port.get_id())
	{
		if (DMI_DLL_TLP_seq_num_cnt != 0)
		{
			DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_in].sequence_number = 0x0;
			DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_in].sequence_number = seq_num_<<8;
			DMI_DLL_TLP_seq_num_cnt--;
		}
		else
		{
			DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_in].sequence_number |= seq_num_;
			DMI_DLL_TLP_seq_num_cnt = 1;
			DMI_current_state = TLP_HEADER;
		}
	}
	else if (id_ == SATA_port.get_id())
	{
		if (SATA_DLL_TLP_seq_num_cnt != 0)
		{
			SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_in].sequence_number = 0x0;
			SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_in].sequence_number = seq_num_<<8;
			SATA_DLL_TLP_seq_num_cnt--;
		}
		else
		{
			SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_in].sequence_number |= seq_num_;
			SATA_DLL_TLP_seq_num_cnt = 1;
			SATA_current_state = TLP_HEADER;
		}
	}
	
	return true;
}

const bool
PCIe_Switch::DLL_send_type_byte(PCIe_id_t	id_,
								byte		type_byte_)
{
	if (id_ == DMI_port.get_id())
	{
		DMI_buffer_DLLP_down[DMI_buffer_DLLP_down_in].type = (PCIe_DLLP_type_t)type_byte_;
		DMI_current_state = DLLP_DATA;
	}
	else if (id_ == SATA_port.get_id())
	{
		SATA_buffer_DLLP_up[SATA_buffer_DLLP_up_in].type = (PCIe_DLLP_type_t)type_byte_;
		SATA_current_state = DLLP_DATA;
	}

	return true;
}

const bool
PCIe_Switch::DLL_send_data_byte(PCIe_id_t	id_,
								byte		data_byte_)
{
	if (id_ == DMI_port.get_id())
	{
		DMI_buffer_DLLP_down[DMI_buffer_DLLP_down_in].data[DMI_DLLP_data_cnt] = data_byte_;
		if (DMI_DLLP_data_cnt != 2)
		{
			DMI_DLLP_data_cnt++;
		}
		else
		{
			DMI_DLLP_data_cnt = 0;
			DMI_current_state = DLLP_CRC;
		}
	}
	else if (id_ == SATA_port.get_id())
	{
		SATA_buffer_DLLP_up[SATA_buffer_DLLP_up_in].data[SATA_DLLP_data_cnt] = data_byte_;
		if (SATA_DLLP_data_cnt != 2)
		{
			SATA_DLLP_data_cnt++;
		}
		else
		{
			SATA_DLLP_data_cnt = 0;
			SATA_current_state = DLLP_CRC;
		}
	}

	return true;
}

const bool
PCIe_Switch::DLL_send_CRC_byte(PCIe_id_t	id_,
							   byte			CRC_byte_)
{
	if (id_ == DMI_port.get_id())
	{
		if (DMI_DLLP_CRC_cnt == 1)
			DMI_buffer_DLLP_down[DMI_buffer_DLLP_down_in].CRC = 0x0;
		DMI_buffer_DLLP_down[DMI_buffer_DLLP_down_in].CRC |= (((unsigned short)CRC_byte_)<<8*DMI_DLLP_CRC_cnt);
		if (DMI_DLLP_CRC_cnt != 0)
		{
			DMI_DLLP_CRC_cnt--;
		}
		else
		{
			DMI_DLLP_CRC_cnt = 1;
			DMI_current_state = PL_IDLE;
		}
	}
	else if (id_ == SATA_port.get_id())
	{
		if (SATA_DLLP_CRC_cnt == 1)
			SATA_buffer_DLLP_up[SATA_buffer_DLLP_up_in].CRC = 0x0;
		SATA_buffer_DLLP_up[SATA_buffer_DLLP_up_in].CRC |= (((unsigned short)CRC_byte_)<<8*SATA_DLLP_CRC_cnt);
		if (SATA_DLLP_CRC_cnt != 0)
		{
			SATA_DLLP_CRC_cnt--;
		}
		else
		{
			SATA_DLLP_CRC_cnt = 1;
			SATA_current_state = PL_IDLE;
		}
	}

	return true;
}

const bool
PCIe_Switch::DLL_send_LCRC_byte(PCIe_id_t	id_,
								byte		LCRC_byte_)
{
	if (id_ == DMI_port.get_id())
	{
		if (DMI_DLL_TLP_LCRC_cnt == 3)
			DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_in].LCRC = 0x0;
		DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_in].LCRC |= (((unsigned)LCRC_byte_)<<8*DMI_DLL_TLP_LCRC_cnt);
		if (DMI_DLL_TLP_LCRC_cnt != 0)
		{
			DMI_DLL_TLP_LCRC_cnt--;
		}
		else
		{
			DMI_DLL_TLP_LCRC_cnt = 3;
			DMI_current_state = PL_IDLE;
		}
	}
	else if (id_ == SATA_port.get_id())
	{
		if (SATA_DLL_TLP_LCRC_cnt == 3)
			SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_in].LCRC = 0x0;
		SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_in].LCRC |= (((unsigned)LCRC_byte_)<<8*SATA_DLL_TLP_LCRC_cnt);
		if (SATA_DLL_TLP_LCRC_cnt != 0)
		{
			SATA_DLL_TLP_LCRC_cnt--;
		}
		else
		{
			SATA_DLL_TLP_LCRC_cnt = 3;
			SATA_current_state = PL_IDLE;
		}
	}

	return true;
}

void
PCIe_Switch::TL_send_header_byte(PCIe_id_t	id_,
								 byte		header_byte_)
{
	if (id_ == DMI_port.get_id())
	{
		if (DMI_TLP_header_cnt == 0)
		{
			if (0x1 & (header_byte_>>5))
			{
				DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_in].TLP.DW4_header = true;
				DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_in].TLP.header = new byte[PCIe_DOUBLE_WORD*4];
			}
			else
			{
				DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_in].TLP.DW4_header = false;
				DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_in].TLP.header = new byte[PCIe_DOUBLE_WORD*3];
			}
			if (0x1 & (header_byte_>>6))
				DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_in].TLP.with_data = true;
			else
				DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_in].TLP.with_data = false;
		}
		DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_in].TLP.header[DMI_TLP_header_cnt] = header_byte_;
		if (DMI_TLP_header_cnt == 2)
		{
			if (header_byte_>>7)
				DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_in].TLP.TLP_digest = true;
			else
				DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_in].TLP.TLP_digest = false;
		}
		else if (DMI_TLP_header_cnt == 3)
		{
			DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_in].TLP.length = (((unsigned short)(0x3 & DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_in].TLP.header[2]))<<8) | ((unsigned short)DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_in].TLP.header[3]);
			if (DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_in].TLP.with_data)
			{
				if (DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_in].TLP.length == 0)
					DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_in].TLP.data = new unsigned[1024];
				else
					DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_in].TLP.data = new unsigned[DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_in].TLP.length];
			}
		}
		DMI_TLP_header_cnt++;
		if (DMI_TLP_header_cnt == 12 && !DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_in].TLP.DW4_header)
		{
			DMI_TLP_header_cnt = 0;
			if (DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_in].TLP.length == 0)
				DMI_current_state = TLP_ECRC;
			else
				DMI_current_state = TLP_DATA;
		}
		if (DMI_TLP_header_cnt == 16 && DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_in].TLP.DW4_header)
		{
			DMI_TLP_header_cnt = 0;
			if (DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_in].TLP.length == 0)
				DMI_current_state = TLP_ECRC;
			else
				DMI_current_state = TLP_DATA;
		}
	}
	else if (id_ == SATA_port.get_id())
	{
		if (SATA_TLP_header_cnt == 0)
		{
			if (0x1 & (header_byte_>>5))
			{
				SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_in].TLP.DW4_header = true;
				SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_in].TLP.header = new byte[PCIe_DOUBLE_WORD*4];
			}
			else
			{
				SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_in].TLP.DW4_header = false;
				SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_in].TLP.header = new byte[PCIe_DOUBLE_WORD*3];
			}
			if (0x1 & (header_byte_>>6))
				SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_in].TLP.with_data = true;
			else
				SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_in].TLP.with_data = false;
		}
		SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_in].TLP.header[SATA_TLP_header_cnt] = header_byte_;
		if (SATA_TLP_header_cnt == 2)
		{
			if (header_byte_>>7)
				SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_in].TLP.TLP_digest = true;
			else
				SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_in].TLP.TLP_digest = false;
		}
		else if (SATA_TLP_header_cnt == 3)
		{
			SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_in].TLP.length = (((unsigned short)(0x3 & SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_in].TLP.header[2]))<<8) | ((unsigned short)SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_in].TLP.header[3]);
			if (SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_in].TLP.with_data)
			{
				if (SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_in].TLP.length == 0)
					SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_in].TLP.data = new unsigned[1024];
				else
					SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_in].TLP.data = new unsigned[SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_in].TLP.length];
			}
		}
		SATA_TLP_header_cnt++;
		if (SATA_TLP_header_cnt == 12 && !SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_in].TLP.DW4_header)
		{
			SATA_TLP_header_cnt = 0;
			if (SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_in].TLP.length == 0)
				SATA_current_state = TLP_ECRC;
			else
				SATA_current_state = TLP_DATA;
		}
		if (SATA_TLP_header_cnt == 16 && SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_in].TLP.DW4_header)
		{
			SATA_TLP_header_cnt = 0;
			if (SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_in].TLP.length == 0)
				SATA_current_state = TLP_ECRC;
			else
				SATA_current_state = TLP_DATA;
		}
	}
}

void
PCIe_Switch::TL_send_data_byte(PCIe_id_t	id_,
							   byte			data_byte_)
{
	if (id_ == DMI_port.get_id())
	{
		switch(DMI_TLP_data_cnt%4)
		{
		case 0:
			DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_in].TLP.data[DMI_TLP_data_cnt/4] = 0;
			DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_in].TLP.data[DMI_TLP_data_cnt/4] |= ((unsigned)data_byte_)<<24;
			break;
		case 1:
			DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_in].TLP.data[DMI_TLP_data_cnt/4] |= ((unsigned)data_byte_)<<16;
			break;
		case 2:
			DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_in].TLP.data[DMI_TLP_data_cnt/4] |= ((unsigned)data_byte_)<<8;
			break;
		case 3:
			DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_in].TLP.data[DMI_TLP_data_cnt/4] |= ((unsigned)data_byte_);
			break;
		}
		DMI_TLP_data_cnt++;
		if (DMI_TLP_data_cnt == DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_in].TLP.length*4)
		{
			DMI_TLP_data_cnt = 0;
			DMI_current_state = TLP_ECRC;
		}
	}
	else if (id_ == SATA_port.get_id())
	{
		switch(SATA_TLP_data_cnt%4)
		{
		case 0:
			SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_in].TLP.data[SATA_TLP_data_cnt/4] = 0;
			SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_in].TLP.data[SATA_TLP_data_cnt/4] |= ((unsigned)data_byte_)<<24;
			break;
		case 1:
			SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_in].TLP.data[SATA_TLP_data_cnt/4] |= ((unsigned)data_byte_)<<16;
			break;
		case 2:
			SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_in].TLP.data[SATA_TLP_data_cnt/4] |= ((unsigned)data_byte_)<<8;
			break;
		case 3:
			SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_in].TLP.data[SATA_TLP_data_cnt/4] |= ((unsigned)data_byte_);
			break;
		}
		SATA_TLP_data_cnt++;
		if (SATA_TLP_data_cnt == SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_in].TLP.length*4)
		{
			SATA_TLP_data_cnt = 0;
			SATA_current_state = TLP_ECRC;
		}
	}
}

void
PCIe_Switch::TL_send_ECRC_byte(PCIe_id_t	id_,
							   byte			ECRC_byte_)
{
	if (id_ == DMI_port.get_id())
	{
		if (DMI_TLP_ECRC_cnt == 3)
			DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_in].TLP.ECRC = 0x0;
		DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_in].TLP.ECRC |= (((unsigned)ECRC_byte_)<<8*DMI_TLP_ECRC_cnt);
		if (DMI_TLP_ECRC_cnt != 0)
		{
			DMI_TLP_ECRC_cnt--;
		}
		else
		{
			DMI_TLP_ECRC_cnt = 3;
			DMI_current_state = TLP_LCRC;
		}
	}
	else if (id_ == SATA_port.get_id())
	{
		if (SATA_TLP_ECRC_cnt == 3)
			SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_in].TLP.ECRC = 0x0;
		SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_in].TLP.ECRC |= (((unsigned)ECRC_byte_)<<8*SATA_TLP_ECRC_cnt);
		if (SATA_TLP_ECRC_cnt != 0)
		{
			SATA_TLP_ECRC_cnt--;
		}
		else
		{
			SATA_TLP_ECRC_cnt = 3;
			SATA_current_state = TLP_LCRC;
		}
	}
}

const bool
PCIe_Switch::arbitrate_port(PCIe_id_t	id_,
							unsigned	packet_type_)
{
	bool return_val = true;

	if (id_ == DMI_port.get_id())
	{
		if ((DMI_buffer_DLL_TLP_up_in != DMI_buffer_DLL_TLP_up_out) && (DMI_buffer_DLLP_up_in != DMI_buffer_DLLP_up_out))
		{
			if (packet_type_ == DMI_granted_packet_type)
				DMI_granted_packet_type = (DMI_granted_packet_type+1)%(DMI_NUM_OF_VIRTUAL_CHANNEL_SWITCH+1);
			else
				return_val = false;
		}
		else
		{
			DMI_granted_packet_type = (packet_type_+1)%(DMI_NUM_OF_VIRTUAL_CHANNEL_SWITCH+1);
		}
	}
	else if (id_ == SATA_port.get_id())
	{
		if ((SATA_buffer_DLL_TLP_down_in != SATA_buffer_DLL_TLP_down_out) && (SATA_buffer_DLLP_down_in != SATA_buffer_DLLP_down_out))
		{
			if (packet_type_ == SATA_granted_packet_type)
				SATA_granted_packet_type = (SATA_granted_packet_type+1)%(SATA_NUM_OF_VIRTUAL_CHANNEL_SWITCH+1);
			else
				return_val = false;
		}
		else
		{
			SATA_granted_packet_type = (packet_type_+1)%(SATA_NUM_OF_VIRTUAL_CHANNEL_SWITCH+1);
		}
	}
		

	return return_val;
}

const unsigned
PCIe_Switch::decode_address(PCIe_address	addr_) const
{
	unsigned return_code;

	for (int i=0;i<switch_address_map.size();i++)
	{
		if ((addr_.high_address >= switch_address_map[i].start_addr.high_address) && (addr_.high_address <= switch_address_map[i].end_addr.high_address))
		{
			if (switch_address_map[i].start_addr.high_address == switch_address_map[i].end_addr.high_address)
			{
				if ((addr_.low_address >= switch_address_map[i].start_addr.low_address) && (addr_.low_address <= switch_address_map[i].end_addr.low_address))
				{
					return_code = i;
					break;
				}
			}
			else
			{
				if (addr_.high_address == switch_address_map[i].start_addr.high_address)
				{
					if (addr_.low_address >= switch_address_map[i].start_addr.low_address)
					{
						return_code = i;
						break;
					}
				}
				else if (addr_.high_address <= switch_address_map[i].end_addr.high_address)
				{
					if (addr_.low_address <= switch_address_map[i].end_addr.low_address)
					{
						return_code = i;
						break;
					}
				}
				else
				{
					return_code = i;
					break;
				}
			}
		}
	}

	sc_assert((return_code>=0) && (return_code<switch_address_map.size()));
	return return_code;
}

void
PCIe_Switch::DMI_switch_action()
{
	bool is_64bit;
	PCIe_address addr;

	while (true)
	{
		is_64bit = false;
		if ((DMI_buffer_TLP_down_in != DMI_buffer_TLP_down_out) && (DMI_buffer_TLP_down_time != sc_time_stamp()))
		{
			switch ((PCIe_TLP_type_t)(DMI_buffer_TLP_down[DMI_buffer_TLP_down_out].header[0] & 0x1F))
			{
			case MEMORY:
			case MEMORY_READ_LOCK:
				if (DMI_buffer_TLP_down[DMI_buffer_TLP_down_out].header[0] == 0x20 || DMI_buffer_TLP_down[DMI_buffer_TLP_down_out].header[0] == 0x21 ||
				    DMI_buffer_TLP_down[DMI_buffer_TLP_down_out].header[0] == 0x60 || DMI_buffer_TLP_down[DMI_buffer_TLP_down_out].header[0] == 0x61)
					is_64bit = true;
			case I_O:
			case MESSAGE_ADDRESS:
				if (is_64bit)
				{
					addr.high_address = (((unsigned)DMI_buffer_TLP_down[DMI_buffer_TLP_down_out].header[8])<<24) | (((unsigned)DMI_buffer_TLP_down[DMI_buffer_TLP_down_out].header[9])<<16) |
										(((unsigned)DMI_buffer_TLP_down[DMI_buffer_TLP_down_out].header[10])<<8) | (((unsigned)DMI_buffer_TLP_down[DMI_buffer_TLP_down_out].header[11]));
					addr.low_address = (((unsigned)DMI_buffer_TLP_down[DMI_buffer_TLP_down_out].header[12])<<24) | (((unsigned)DMI_buffer_TLP_down[DMI_buffer_TLP_down_out].header[13])<<16) |
									   (((unsigned)DMI_buffer_TLP_down[DMI_buffer_TLP_down_out].header[14])<<8) | (((unsigned)DMI_buffer_TLP_down[DMI_buffer_TLP_down_out].header[15]));
				}
				else
				{
					addr.high_address = 0x0;
					addr.low_address = (((unsigned)DMI_buffer_TLP_down[DMI_buffer_TLP_down_out].header[8])<<24) | (((unsigned)DMI_buffer_TLP_down[DMI_buffer_TLP_down_out].header[9])<<16) |
									   (((unsigned)DMI_buffer_TLP_down[DMI_buffer_TLP_down_out].header[10])<<8) | (((unsigned)DMI_buffer_TLP_down[DMI_buffer_TLP_down_out].header[11]));
				}
				switch (decode_address(addr))
				{
				case 0:
				case 1:
				case 2:
				case 3:
					if ((SATA_buffer_TLP_down_in+1)%MAX_BUFFER_SWITCH != SATA_buffer_TLP_down_out)
					{
						SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].with_data = DMI_buffer_TLP_down[DMI_buffer_TLP_down_out].with_data;
						SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].DW4_header = DMI_buffer_TLP_down[DMI_buffer_TLP_down_out].DW4_header;
						int limit;
						if (SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].DW4_header)
						{
							SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].header = new byte[PCIe_DOUBLE_WORD*4];
							limit = 16;
						}
						else
						{
							SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].header = new byte[PCIe_DOUBLE_WORD*3];
							limit = 12;
						}
						for (int i=0;i<limit;i++)
							SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].header[i] = DMI_buffer_TLP_down[DMI_buffer_TLP_down_out].header[i];
						SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].length = DMI_buffer_TLP_down[DMI_buffer_TLP_down_out].length;
						if (SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].with_data)
						{
							if (SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].length == 0)
							{
								SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].data = new unsigned[1024];
								for (int i=0;i<1024;i++)
									SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].data[i] = DMI_buffer_TLP_down[DMI_buffer_TLP_down_out].data[i];
							}
							else
							{
								SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].data = new unsigned[SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].length];
								for (int i=0;i<SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].length;i++)
									SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].data[i] = DMI_buffer_TLP_down[DMI_buffer_TLP_down_out].data[i];
							}
						}
						SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].TLP_digest = DMI_buffer_TLP_down[DMI_buffer_TLP_down_out].TLP_digest;
						SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].ECRC = DMI_buffer_TLP_down[DMI_buffer_TLP_down_out].ECRC;
#ifdef	DEBUG_SWITCH
						cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Switch to SATA" << endl;
						cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "SATA TLP Header : ";
						for (int i=0; i<limit ; i++)
						{
							cout.width(2);
							cout.fill('0');
							cout << hex << (unsigned)SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].header[i] << dec << " ";
						}
						cout << endl;
						if (SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].with_data)
						{
							cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "SATA TLP Data : ";
							if (SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].length == 0)
							{
								for (int i=0; i<1024*PCIe_DOUBLE_WORD; i++)
								{
									cout.width(2);
									cout.fill('0');
									switch (i%4)
									{
									case 0:
										cout << hex << ((SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].data[i/4]>>24) & 0xFF) << dec << " ";
										break;
									case 1:
										cout << hex << ((SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].data[i/4]>>16) & 0xFF) << dec << " ";
										break;
									case 2:
										cout << hex << ((SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].data[i/4]>>8) & 0xFF) << dec << " ";
										break;
									case 3:
										cout << hex << (SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].data[i/4] & 0xFF) << dec << " | ";
										break;
									}
								}
							}
							else
							{
								for (int i=0; i<SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].length*PCIe_DOUBLE_WORD; i++)
								{
									cout.width(2);
									cout.fill('0');
									switch (i%4)
									{
									case 0:
										cout << hex << ((SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].data[i/4]>>24) & 0xFF) << dec << " ";
										break;
									case 1:
										cout << hex << ((SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].data[i/4]>>16) & 0xFF) << dec << " ";
										break;
									case 2:
										cout << hex << ((SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].data[i/4]>>8) & 0xFF) << dec << " ";
										break;
									case 3:
										cout << hex << (SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].data[i/4] & 0xFF) << dec << " | ";
										break;
									}
								}
							}
							cout << endl;						
						}
						cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "SATA TLP ECRC : " << hex << SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].ECRC << dec << endl;
#endif
						SATA_buffer_TLP_down_in = (SATA_buffer_TLP_down_in+1)%MAX_BUFFER_SWITCH;
						SATA_buffer_TLP_down_time = sc_time_stamp();
						delete[] DMI_buffer_TLP_down[DMI_buffer_TLP_down_out].header;
						if (DMI_buffer_TLP_down[DMI_buffer_TLP_down_out].with_data)
							delete[] DMI_buffer_TLP_down[DMI_buffer_TLP_down_out].data;
						DMI_buffer_TLP_down_out = (DMI_buffer_TLP_down_out+1)%MAX_BUFFER_SWITCH;
					}
					break;
				}
				break;
			case CONFIGURATION_TYPE0:
			case CONFIGURATION_TYPE1:
			case COMPLETION:
			case COMPLETION_LOCK:
			case MESSAGE_ID:
			case MESSAGE_BROADCAST:
				if (DMI_buffer_TLP_down[DMI_buffer_TLP_down_out].header[8] == 0)
				{
					if (DMI_buffer_TLP_down[DMI_buffer_TLP_down_out].header[9] == SATA_CONTROLLER_1_ID || DMI_buffer_TLP_down[DMI_buffer_TLP_down_out].header[9] == SATA_CONTROLLER_2_ID)
					{
						if ((SATA_buffer_TLP_down_in+1)%MAX_BUFFER_SWITCH != SATA_buffer_TLP_down_out)
						{
							SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].with_data = DMI_buffer_TLP_down[DMI_buffer_TLP_down_out].with_data;
							SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].DW4_header = DMI_buffer_TLP_down[DMI_buffer_TLP_down_out].DW4_header;
							int limit;
							if (SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].DW4_header)
							{
								SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].header = new byte[PCIe_DOUBLE_WORD*4];
								limit = 16;
							}
							else
							{
								SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].header = new byte[PCIe_DOUBLE_WORD*3];
								limit = 12;
							}
							for (int i=0;i<limit;i++)
								SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].header[i] = DMI_buffer_TLP_down[DMI_buffer_TLP_down_out].header[i];
							SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].length = DMI_buffer_TLP_down[DMI_buffer_TLP_down_out].length;
							if (SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].with_data)
							{
								if (SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].length == 0)
								{
									SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].data = new unsigned[1024];
									for (int i=0;i<1024;i++)
										SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].data[i] = DMI_buffer_TLP_down[DMI_buffer_TLP_down_out].data[i];
								}
								else
								{
									SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].data = new unsigned[SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].length];
									for (int i=0;i<SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].length;i++)
										SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].data[i] = DMI_buffer_TLP_down[DMI_buffer_TLP_down_out].data[i];
								}
							}
							SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].TLP_digest = DMI_buffer_TLP_down[DMI_buffer_TLP_down_out].TLP_digest;
							SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].ECRC = DMI_buffer_TLP_down[DMI_buffer_TLP_down_out].ECRC;
#ifdef	DEBUG_SWITCH
							cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Switch to SATA" << endl;
							cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "SATA TLP Header : ";
							for (int i=0; i<limit ; i++)
							{
								cout.width(2);
								cout.fill('0');
								cout << hex << (unsigned)SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].header[i] << dec << " ";
							}
							cout << endl;
							if (SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].with_data)
							{
								cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "SATA TLP Data : ";
								if (SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].length == 0)
								{
									for (int i=0; i<1024*PCIe_DOUBLE_WORD; i++)
									{
										cout.width(2);
										cout.fill('0');
										switch (i%4)
										{
										case 0:
											cout << hex << ((SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].data[i/4]>>24) & 0xFF) << dec << " ";
											break;
										case 1:
											cout << hex << ((SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].data[i/4]>>16) & 0xFF) << dec << " ";
											break;
										case 2:
											cout << hex << ((SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].data[i/4]>>8) & 0xFF) << dec << " ";
											break;
										case 3:
											cout << hex << (SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].data[i/4] & 0xFF) << dec << " | ";
											break;
										}
									}
								}
								else
								{
									for (int i=0; i<SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].length*PCIe_DOUBLE_WORD; i++)
									{
										cout.width(2);
										cout.fill('0');
										switch (i%4)
										{
										case 0:
											cout << hex << ((SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].data[i/4]>>24) & 0xFF) << dec << " ";
											break;
										case 1:
											cout << hex << ((SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].data[i/4]>>16) & 0xFF) << dec << " ";
											break;
										case 2:
											cout << hex << ((SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].data[i/4]>>8) & 0xFF) << dec << " ";
											break;
										case 3:
											cout << hex << (SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].data[i/4] & 0xFF) << dec << " | ";
											break;
										}
									}
								}
								cout << endl;
							}
							cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "SATA TLP ECRC : " << hex << SATA_buffer_TLP_down[SATA_buffer_TLP_down_in].ECRC << dec << endl;
#endif
							SATA_buffer_TLP_down_in = (SATA_buffer_TLP_down_in+1)%MAX_BUFFER_SWITCH;
							SATA_buffer_TLP_down_time = sc_time_stamp();
							delete[] DMI_buffer_TLP_down[DMI_buffer_TLP_down_out].header;
							if (DMI_buffer_TLP_down[DMI_buffer_TLP_down_out].with_data)
								delete[] DMI_buffer_TLP_down[DMI_buffer_TLP_down_out].data;
							DMI_buffer_TLP_down_out = (DMI_buffer_TLP_down_out+1)%MAX_BUFFER_SWITCH;
						}
					}
				}
				break;
			case MESSAGE_RC:
			case MESSAGE_LOCAL:
			case MESSAGE_GATHERED_TO_RC:
				DMI_buffer_TLP_down_out = (DMI_buffer_TLP_down_out+1)%MAX_BUFFER_SWITCH;
				break;
			}
		}
		wait();
	}
}

void
PCIe_Switch::SATA_switch_action()
{
	while (true)
	{
		if ((SATA_buffer_TLP_up_in != SATA_buffer_TLP_up_out) && (SATA_buffer_TLP_up_time != sc_time_stamp()))
		{
			if ((DMI_buffer_TLP_up_in+1)%MAX_BUFFER_SWITCH != DMI_buffer_TLP_up_out)
			{
				DMI_buffer_TLP_up[DMI_buffer_TLP_up_in].with_data = SATA_buffer_TLP_up[SATA_buffer_TLP_up_out].with_data;
				DMI_buffer_TLP_up[DMI_buffer_TLP_up_in].DW4_header = SATA_buffer_TLP_up[SATA_buffer_TLP_up_out].DW4_header;
				int limit;
				if (DMI_buffer_TLP_up[DMI_buffer_TLP_up_in].DW4_header)
				{
					DMI_buffer_TLP_up[DMI_buffer_TLP_up_in].header = new byte[PCIe_DOUBLE_WORD*4];
					limit = 16;
				}
				else
				{
					DMI_buffer_TLP_up[DMI_buffer_TLP_up_in].header = new byte[PCIe_DOUBLE_WORD*3];
					limit = 12;
				}
				for (int i=0;i<limit;i++)
					DMI_buffer_TLP_up[DMI_buffer_TLP_up_in].header[i] = SATA_buffer_TLP_up[SATA_buffer_TLP_up_out].header[i];
				DMI_buffer_TLP_up[DMI_buffer_TLP_up_in].length = SATA_buffer_TLP_up[SATA_buffer_TLP_up_out].length;
				if (DMI_buffer_TLP_up[DMI_buffer_TLP_up_in].with_data)
				{
					if (DMI_buffer_TLP_up[DMI_buffer_TLP_up_in].length == 0)
					{
						DMI_buffer_TLP_up[DMI_buffer_TLP_up_in].data = new unsigned[1024];
						for (int i=0;i<1024;i++)
							DMI_buffer_TLP_up[DMI_buffer_TLP_up_in].data[i] = SATA_buffer_TLP_up[SATA_buffer_TLP_up_out].data[i];
					}
					else
					{
						DMI_buffer_TLP_up[DMI_buffer_TLP_up_in].data = new unsigned[DMI_buffer_TLP_up[DMI_buffer_TLP_up_in].length];
						for (int i=0;i<DMI_buffer_TLP_up[DMI_buffer_TLP_up_in].length;i++)
							DMI_buffer_TLP_up[DMI_buffer_TLP_up_in].data[i] = SATA_buffer_TLP_up[SATA_buffer_TLP_up_out].data[i];
					}
				}
				DMI_buffer_TLP_up[DMI_buffer_TLP_up_in].TLP_digest = SATA_buffer_TLP_up[SATA_buffer_TLP_up_out].TLP_digest;
				DMI_buffer_TLP_up[DMI_buffer_TLP_up_in].ECRC = SATA_buffer_TLP_up[SATA_buffer_TLP_up_out].ECRC;
#ifdef	DEBUG_SWITCH
				cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Switch to DMI" << endl;
				cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "DMI TLP Header : ";
				for (int i=0; i<limit ; i++)
				{
					cout.width(2);
					cout.fill('0');
					cout << hex << (unsigned)DMI_buffer_TLP_up[DMI_buffer_TLP_up_in].header[i] << dec << " ";
				}
				cout << endl;
				if (DMI_buffer_TLP_up[DMI_buffer_TLP_up_in].with_data)
				{
					cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "DMI TLP Data : ";
					if (DMI_buffer_TLP_up[DMI_buffer_TLP_up_in].length == 0)
					{
						for (int i=0; i<1024*PCIe_DOUBLE_WORD; i++)
						{
							cout.width(2);
							cout.fill('0');
							switch (i%4)
							{
							case 0:
								cout << hex << ((DMI_buffer_TLP_up[DMI_buffer_TLP_up_in].data[i/4]>>24) & 0xFF) << dec << " ";
								break;
							case 1:
								cout << hex << ((DMI_buffer_TLP_up[DMI_buffer_TLP_up_in].data[i/4]>>16) & 0xFF) << dec << " ";
								break;
							case 2:
								cout << hex << ((DMI_buffer_TLP_up[DMI_buffer_TLP_up_in].data[i/4]>>8) & 0xFF) << dec << " ";
								break;
							case 3:
								cout << hex << (DMI_buffer_TLP_up[DMI_buffer_TLP_up_in].data[i/4] & 0xFF) << dec << " | ";
								break;
							}
						}
					}
					else
					{
						for (int i=0; i<DMI_buffer_TLP_up[DMI_buffer_TLP_up_in].length*PCIe_DOUBLE_WORD; i++)
						{
							cout.width(2);
							cout.fill('0');
							switch (i%4)
							{
							case 0:
								cout << hex << ((DMI_buffer_TLP_up[DMI_buffer_TLP_up_in].data[i/4]>>24) & 0xFF) << dec << " ";
								break;
							case 1:
								cout << hex << ((DMI_buffer_TLP_up[DMI_buffer_TLP_up_in].data[i/4]>>16) & 0xFF) << dec << " ";
								break;
							case 2:
								cout << hex << ((DMI_buffer_TLP_up[DMI_buffer_TLP_up_in].data[i/4]>>8) & 0xFF) << dec << " ";
								break;
							case 3:
								cout << hex << (DMI_buffer_TLP_up[DMI_buffer_TLP_up_in].data[i/4] & 0xFF) << dec << " | ";
								break;
							}
						}
					}
					cout << endl;
				}
				cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "DMI TLP ECRC : " << hex << DMI_buffer_TLP_up[DMI_buffer_TLP_up_in].ECRC << dec << endl;
#endif
				DMI_buffer_TLP_up_in = (DMI_buffer_TLP_up_in+1)%MAX_BUFFER_SWITCH;
				DMI_buffer_TLP_up_time = sc_time_stamp();
				delete[] SATA_buffer_TLP_up[SATA_buffer_TLP_up_out].header;
				if (SATA_buffer_TLP_up[SATA_buffer_TLP_up_out].with_data)
					delete[] SATA_buffer_TLP_up[SATA_buffer_TLP_up_out].data;
				SATA_buffer_TLP_up_out = (SATA_buffer_TLP_up_out+1)%MAX_BUFFER_SWITCH;
			}
		}
		wait();
	}
}

void
PCIe_Switch::DMI_make_action()
{
	PCIe_DLL_TLP dll_tlp;

	while (true)
	{
		if ((DMI_buffer_TLP_up_in != DMI_buffer_TLP_up_out) && ((DMI_buffer_DLL_TLP_up_in+1)%MAX_BUFFER_SWITCH != DMI_buffer_DLL_TLP_up_ack_nak) && (DMI_buffer_TLP_up_time != sc_time_stamp()))
		{
			if (DMI_NAK_sequence_number < DMI_sequence_number)
				break;
			dll_tlp = construct_DLL_TLP(DMI_sequence_number++%4096, DMI_buffer_TLP_up[DMI_buffer_TLP_up_out], 0);
			DMI_NAK_sequence_number++;
#ifdef	DEBUG_SWITCH
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Target Buffer : DMI" << endl;
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Sequence Number : " << hex << dll_tlp.sequence_number << dec << endl;
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "TLP Header : ";
			if (dll_tlp.TLP.DW4_header)
				for (int i=0; i<4*4; i++)
				{
					cout.width(2);
					cout.fill('0');
					cout << hex << (unsigned)dll_tlp.TLP.header[i] << dec << " ";
				}
			else
				for (int i=0; i<3*4; i++)
				{
					cout.width(2);
					cout.fill('0');
					cout << hex << (unsigned)dll_tlp.TLP.header[i] << dec << " ";
				}
			cout << endl;
			if (dll_tlp.TLP.with_data)
			{
				cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "TLP Data : ";
				if (dll_tlp.TLP.length == 0)
				{
					for (int i=0; i<1024*PCIe_DOUBLE_WORD; i++)
					{
						cout.width(2);
						cout.fill('0');
						switch (i%4)
						{
						case 0:
							cout << hex << ((dll_tlp.TLP.data[i/4]>>24) & 0xFF) << dec << " ";
							break;
						case 1:
							cout << hex << ((dll_tlp.TLP.data[i/4]>>16) & 0xFF) << dec << " ";
							break;
						case 2:
							cout << hex << ((dll_tlp.TLP.data[i/4]>>8) & 0xFF) << dec << " ";
							break;
						case 3:
							cout << hex << (dll_tlp.TLP.data[i/4] & 0xFF) << dec << " | ";
							break;
						}
					}
				}
				else
				{
					for (int i=0; i<dll_tlp.TLP.length*PCIe_DOUBLE_WORD; i++)
					{
						cout.width(2);
						cout.fill('0');
						switch (i%4)
						{
						case 0:
							cout << hex << ((dll_tlp.TLP.data[i/4]>>24) & 0xFF) << dec << " ";
							break;
						case 1:
							cout << hex << ((dll_tlp.TLP.data[i/4]>>16) & 0xFF) << dec << " ";
							break;
						case 2:
							cout << hex << ((dll_tlp.TLP.data[i/4]>>8) & 0xFF) << dec << " ";
							break;
						case 3:
							cout << hex << (dll_tlp.TLP.data[i/4] & 0xFF) << dec << " | ";
							break;
						}
					}
				}
				cout << endl;
			}
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "TLP ECRC : " << hex << dll_tlp.TLP.ECRC << dec << endl;
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "LCRC : " << hex << dll_tlp.LCRC << dec << endl;
#endif
			DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in] = dll_tlp;
			DMI_buffer_TLP_up_out = (DMI_buffer_TLP_up_out+1)%MAX_BUFFER_SWITCH;
			DMI_buffer_DLL_TLP_up_in = (DMI_buffer_DLL_TLP_up_in+1)%MAX_BUFFER_SWITCH;
			DMI_buffer_DLL_TLP_up_time = sc_time_stamp();
		}
		wait();
	}
}

void
PCIe_Switch::DMI_TLP_send_action()
{
	unsigned	wait_cnt;

	DMI_lane = DMI_port.lane_width();

	while(true)
	{
		wait_cnt = 0;
		if ((DMI_buffer_DLL_TLP_up_in != DMI_buffer_DLL_TLP_up_out) &&
			(!DMI_port.is_in_use()) &&
			(DMI_port.check_release_time() != sc_time_stamp()) &&
			((DMI_buffer_DLL_TLP_up_time != sc_time_stamp()) || (DMI_buffer_DLL_TLP_up_in != (DMI_buffer_DLL_TLP_up_out+1)%MAX_BUFFER_SWITCH)) &&
			(arbitrate_port(DMI_port.get_id(),1)))
		{
			if (DMI_stop)
			{
				DMI_stop = false;
				wait();
				continue;
			}
			DMI_port.set_in_use(true);
			DMI_port.PL_send_symbol(STP);
#ifdef	DEBUG_SWITCH
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Send STP Symbol to DMI Port." << endl;
#endif
			wait_cnt++;
			if (wait_cnt%DMI_lane == 0)
				wait();
			if ((DMI_stop) && (DMI_buffer_DLLP_down_time != sc_time_stamp()))
			{
				DMI_stop = false;
				DMI_port.set_in_use(false);
				wait();
				continue;
			}

			DMI_port.DLL_send_sequence_number_byte((byte)(DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_out].sequence_number>>8));
#ifdef	DEBUG_SWITCH
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Send Sequence Number to DMI Port : ";
			cout.width(2);
			cout.fill('0');
			cout << hex << (DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_out].sequence_number>>8) << dec << "." << endl;
#endif
			wait_cnt++;
			if (wait_cnt%DMI_lane == 0)
				wait();
			if ((DMI_stop) && (DMI_buffer_DLLP_down_time != sc_time_stamp()))
			{
				DMI_stop = false;
				DMI_port.set_in_use(false);
				wait();
				continue;
			}

			DMI_port.DLL_send_sequence_number_byte((byte)(DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_out].sequence_number));
#ifdef	DEBUG_SWITCH
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Send Sequence Number to DMI Port : ";
			cout.width(2);
			cout.fill('0');
			cout << hex << DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_out].sequence_number << dec << "." << endl;
#endif
			wait_cnt++;
			if (wait_cnt%DMI_lane == 0)
				wait();
			if ((DMI_stop) && (DMI_buffer_DLLP_down_time != sc_time_stamp()))
			{
				DMI_stop = false;
				DMI_port.set_in_use(false);
				wait();
				continue;
			}

			if (DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_out].TLP.DW4_header)
			{
				for (int i=0;i<4*4;i++)
				{
					DMI_port.TL_send_header_byte(DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_out].TLP.header[i]);
#ifdef	DEBUG_SWITCH
					cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Send TLP Header to DMI Port : ";
					cout.width(2);
					cout.fill('0');
					cout << hex << (unsigned)DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_out].TLP.header[i] << dec << "." << endl;
#endif
					wait_cnt++;
					if (wait_cnt%DMI_lane == 0)
						wait();
					if ((DMI_stop) && (DMI_buffer_DLLP_down_time != sc_time_stamp()))
						break;
				}
				if ((DMI_stop) && (DMI_buffer_DLLP_down_time != sc_time_stamp()))
				{
					DMI_stop = false;
					DMI_port.set_in_use(false);
					wait();
					continue;
				}
			}
			else
			{
				for (int i=0;i<3*4;i++)
				{
					DMI_port.TL_send_header_byte(DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_out].TLP.header[i]);
#ifdef	DEBUG_SWITCH
					cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Send TLP Header to DMI Port : ";
					cout.width(2);
					cout.fill('0');
					cout << hex << (unsigned)DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_out].TLP.header[i] << dec << "." << endl;
#endif
					wait_cnt++;
					if (wait_cnt%DMI_lane == 0)
						wait();
					if ((DMI_stop) && (DMI_buffer_DLLP_down_time != sc_time_stamp()))
						break;
				}
				if ((DMI_stop) && (DMI_buffer_DLLP_down_time != sc_time_stamp()))
				{
					DMI_stop = false;
					DMI_port.set_in_use(false);
					wait();
					continue;
				}
			}

			if (DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_out].TLP.with_data)
			{
				if (DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_out].TLP.length == 0)
				{
					for (int i=0;i<1024*PCIe_DOUBLE_WORD;i++)
					{
						switch (i%4)
						{
						case 0:
							DMI_port.TL_send_data_byte((byte)(DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_out].TLP.data[i/4]>>24));
							break;
						case 1:
							DMI_port.TL_send_data_byte((byte)(DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_out].TLP.data[i/4]>>16));
							break;
						case 2:
							DMI_port.TL_send_data_byte((byte)(DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_out].TLP.data[i/4]>>8));
							break;
						case 3:
							DMI_port.TL_send_data_byte((byte)DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_out].TLP.data[i/4]);
							break;
						}
#ifdef	DEBUG_SWITCH
						cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Send TLP Data to DMI Port : ";
						cout.width(2);
						cout.fill('0');
						switch (i%4)
						{
						case 0:
							cout << hex << ((DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_out].TLP.data[i/4]>>24) & 0xFF) << dec << "." << endl;
							break;
						case 1:
							cout << hex << ((DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_out].TLP.data[i/4]>>16) & 0xFF) << dec << "." << endl;
							break;
						case 2:
							cout << hex << ((DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_out].TLP.data[i/4]>>8) & 0xFF) << dec << "." << endl;
							break;
						case 3:
							cout << hex << (DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_out].TLP.data[i/4] & 0xFF) << dec << "." << endl;
							break;
						}
#endif
						wait_cnt++;
						if (wait_cnt%DMI_lane == 0)
							wait();
						if ((DMI_stop) && (DMI_buffer_DLLP_down_time != sc_time_stamp()))
							break;
					}
				}
				else
				{
					for (int i=0;i<DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_out].TLP.length*4;i++)
					{
						switch (i%4)
						{
						case 0:
							DMI_port.TL_send_data_byte((byte)(DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_out].TLP.data[i/4]>>24));
							break;
						case 1:
							DMI_port.TL_send_data_byte((byte)(DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_out].TLP.data[i/4]>>16));
							break;
						case 2:
							DMI_port.TL_send_data_byte((byte)(DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_out].TLP.data[i/4]>>8));
							break;
						case 3:
							DMI_port.TL_send_data_byte((byte)DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_out].TLP.data[i/4]);
							break;
						}
#ifdef	DEBUG_SWITCH
						cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Send TLP Data to DMI Port : ";
						cout.width(2);
						cout.fill('0');
						switch (i%4)
						{
						case 0:
							cout << hex << ((DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_out].TLP.data[i/4]>>24) & 0xFF) << dec << "." << endl;
							break;
						case 1:
							cout << hex << ((DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_out].TLP.data[i/4]>>16) & 0xFF) << dec << "." << endl;
							break;
						case 2:
							cout << hex << ((DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_out].TLP.data[i/4]>>8) & 0xFF) << dec << "." << endl;
							break;
						case 3:
							cout << hex << (DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_out].TLP.data[i/4] & 0xFF) << dec << "." << endl;
							break;
						}
#endif
						wait_cnt++;
						if (wait_cnt%DMI_lane == 0)
							wait();
						if ((DMI_stop) && (DMI_buffer_DLLP_down_time != sc_time_stamp()))
							break;
					}
				}
				if ((DMI_stop) && (DMI_buffer_DLLP_down_time != sc_time_stamp()))
				{
					DMI_stop = false;
					DMI_port.set_in_use(false);
					wait();
					continue;
				}
			}

			if (DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_out].TLP.TLP_digest)
			{
				for (int i=3;i>=0;i--)
				{
					DMI_port.TL_send_ECRC_byte(DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_out].TLP.ECRC>>(8*i));
#ifdef	DEBUG_SWITCH
					cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Send TLP ECRC to DMI Port : ";
					cout.width(2);
					cout.fill('0');
					cout << hex << (unsigned)(DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_out].TLP.ECRC>>(8*i)) << dec << "." << endl;
#endif
					wait_cnt++;
					if (wait_cnt%DMI_lane == 0)
						wait();
					if ((DMI_stop) && (DMI_buffer_DLLP_down_time != sc_time_stamp()))
						break;
				}
				if ((DMI_stop) && (DMI_buffer_DLLP_down_time != sc_time_stamp()))
				{
					DMI_stop = false;
					DMI_port.set_in_use(false);
					wait();
					continue;
				}
			}

			for (int i=3;i>=0;i--)
			{
				DMI_port.DLL_send_LCRC_byte(DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_out].LCRC>>(8*i));
#ifdef	DEBUG_SWITCH
				cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Send LCRC to DMI Port : ";
				cout.width(2);
				cout.fill('0');
				cout << hex << (unsigned)(DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_out].LCRC>>(8*i)) << dec << "." << endl;
#endif
				wait_cnt++;
				if (wait_cnt%DMI_lane == 0)
					wait();
				if ((DMI_stop) && (DMI_buffer_DLLP_down_time != sc_time_stamp()))
					break;
			}
			if ((DMI_stop) && (DMI_buffer_DLLP_down_time != sc_time_stamp()))
			{
				DMI_stop = false;
				DMI_port.set_in_use(false);
				wait();
				continue;
			}

			DMI_port.PL_send_symbol(END);
			DMI_port.set_in_use(false);
#ifdef	DEBUG_SWITCH
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Send END Symbol to DMI Port." << endl;
#endif
			DMI_buffer_DLL_TLP_up_out = (DMI_buffer_DLL_TLP_up_out+1)%MAX_BUFFER_SWITCH; 
			if (DMI_sequence_number > DMI_NAK_sequence_number)
				DMI_NAK_sequence_number++;
#ifdef	DEBUG_SWITCH
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "SEND DLL_TLP to DMI Port Complete!" << endl;
#endif
		}
		wait();
	}
}

void
PCIe_Switch::SATA_make_action()
{
	PCIe_DLL_TLP dll_tlp;

	while (true)
	{
		if ((SATA_buffer_TLP_down_in != SATA_buffer_TLP_down_out) && ((SATA_buffer_DLL_TLP_down_in+1)%MAX_BUFFER_SWITCH != SATA_buffer_DLL_TLP_down_ack_nak) && (SATA_buffer_TLP_down_time != sc_time_stamp()))
		{
			if (SATA_NAK_sequence_number < SATA_sequence_number)
				break;
			dll_tlp = construct_DLL_TLP(SATA_sequence_number++%4096, SATA_buffer_TLP_down[SATA_buffer_TLP_down_out], 0);
			SATA_NAK_sequence_number++;
#ifdef	DEBUG_SWITCH
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Target Buffer : SATA" << endl;
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Sequence Number : " << hex << dll_tlp.sequence_number << dec << endl;
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "TLP Header : ";
			if (dll_tlp.TLP.DW4_header)
				for (int i=0; i<4*4; i++)
				{
					cout.width(2);
					cout.fill('0');
					cout << hex << (unsigned)dll_tlp.TLP.header[i] << dec << " ";
				}
			else
				for (int i=0; i<3*4; i++)
				{
					cout.width(2);
					cout.fill('0');
					cout << hex << (unsigned)dll_tlp.TLP.header[i] << dec << " ";
				}
			cout << endl;
			if (dll_tlp.TLP.with_data)
			{
				cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "TLP Data : ";
				if (dll_tlp.TLP.length == 0)
				{
					for (int i=0; i<1024*PCIe_DOUBLE_WORD; i++)
					{
						cout.width(2);
						cout.fill('0');
						switch (i%4)
						{
						case 0:
							cout << hex << ((dll_tlp.TLP.data[i/4]>>24) & 0xFF) << dec << " ";
							break;
						case 1:
							cout << hex << ((dll_tlp.TLP.data[i/4]>>16) & 0xFF) << dec << " ";
							break;
						case 2:
							cout << hex << ((dll_tlp.TLP.data[i/4]>>8) & 0xFF) << dec << " ";
							break;
						case 3:
							cout << hex << (dll_tlp.TLP.data[i/4] & 0xFF) << dec << " | ";
							break;
						}
					}
				}
				else
				{
					for (int i=0; i<dll_tlp.TLP.length*PCIe_DOUBLE_WORD; i++)
					{
						cout.width(2);
						cout.fill('0');
						switch (i%4)
						{
						case 0:
							cout << hex << ((dll_tlp.TLP.data[i/4]>>24) & 0xFF) << dec << " ";
							break;
						case 1:
							cout << hex << ((dll_tlp.TLP.data[i/4]>>16) & 0xFF) << dec << " ";
							break;
						case 2:
							cout << hex << ((dll_tlp.TLP.data[i/4]>>8) & 0xFF) << dec << " ";
							break;
						case 3:
							cout << hex << (dll_tlp.TLP.data[i/4] & 0xFF) << dec << " | ";
							break;
						}
					}
				}
				cout << endl;
			}
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "TLP ECRC : " << hex << dll_tlp.TLP.ECRC << dec << endl;
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "LCRC : " << hex << dll_tlp.LCRC << dec << endl;
#endif
			SATA_buffer_DLL_TLP_down[SATA_buffer_DLL_TLP_down_in] = dll_tlp;
			SATA_buffer_TLP_down_out = (SATA_buffer_TLP_down_out+1)%MAX_BUFFER_SWITCH;
			SATA_buffer_DLL_TLP_down_in = (SATA_buffer_DLL_TLP_down_in+1)%MAX_BUFFER_SWITCH;
			SATA_buffer_DLL_TLP_down_time = sc_time_stamp();
		}
		wait();
	}
}

void
PCIe_Switch::SATA_TLP_send_action()
{
	unsigned	wait_cnt;

	SATA_lane = SATA_port.lane_width();

	while(true)
	{
		wait_cnt = 0;
		if ((SATA_buffer_DLL_TLP_down_in != SATA_buffer_DLL_TLP_down_out) &&
			(!SATA_port.is_in_use()) &&
			(SATA_port.check_release_time() != sc_time_stamp()) &&
			((SATA_buffer_DLL_TLP_down_time != sc_time_stamp()) || (SATA_buffer_DLL_TLP_down_in != (SATA_buffer_DLL_TLP_down_out+1)%MAX_BUFFER_SWITCH)) &&
			(arbitrate_port(SATA_port.get_id(),1)))
		{
			if ((SATA_stop) && (SATA_buffer_DLLP_up_time != sc_time_stamp()))
			{
				SATA_stop = false;
				continue;
			}
			SATA_port.set_in_use(true);
			SATA_port.PL_send_symbol(STP);
#ifdef	DEBUG_SWITCH
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Send STP Symbol to SATA Port." << endl;
#endif
			wait_cnt++;
			if (wait_cnt%SATA_lane == 0)
				wait();
			if ((SATA_stop) && (SATA_buffer_DLLP_up_time != sc_time_stamp()))
			{
				SATA_stop = false;
				SATA_port.set_in_use(false);
				wait();
				continue;
			}

			SATA_port.DLL_send_sequence_number_byte((byte)(SATA_buffer_DLL_TLP_down[SATA_buffer_DLL_TLP_down_out].sequence_number>>8));
#ifdef	DEBUG_SWITCH
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Send Sequence Number to SATA Port : ";
			cout.width(2);
			cout.fill('0');
			cout << hex << (SATA_buffer_DLL_TLP_down[SATA_buffer_DLL_TLP_down_out].sequence_number>>8) << dec << "." << endl;
#endif
			wait_cnt++;
			if (wait_cnt%SATA_lane == 0)
				wait();
			if ((SATA_stop) && (SATA_buffer_DLLP_up_time != sc_time_stamp()))
			{
				SATA_stop = false;
				SATA_port.set_in_use(false);
				wait();
				continue;
			}

			SATA_port.DLL_send_sequence_number_byte((byte)(SATA_buffer_DLL_TLP_down[SATA_buffer_DLL_TLP_down_out].sequence_number));
#ifdef	DEBUG_SWITCH
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Send Sequence Number to SATA Port : ";
			cout.width(2);
			cout.fill('0');
			cout << hex << SATA_buffer_DLL_TLP_down[SATA_buffer_DLL_TLP_down_out].sequence_number << dec << "." << endl;
#endif
			wait_cnt++;
			if (wait_cnt%SATA_lane == 0)
				wait();
			if ((SATA_stop) && (SATA_buffer_DLLP_up_time != sc_time_stamp()))
			{
				SATA_stop = false;
				SATA_port.set_in_use(false);
				wait();
				continue;
			}

			if (SATA_buffer_DLL_TLP_down[SATA_buffer_DLL_TLP_down_out].TLP.DW4_header)
			{
				for (int i=0;i<4*4;i++)
				{
					SATA_port.TL_send_header_byte(SATA_buffer_DLL_TLP_down[SATA_buffer_DLL_TLP_down_out].TLP.header[i]);
#ifdef	DEBUG_SWITCH
					cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Send TLP Header to SATA Port : ";
					cout.width(2);
					cout.fill('0');
					cout << hex << (unsigned)SATA_buffer_DLL_TLP_down[SATA_buffer_DLL_TLP_down_out].TLP.header[i] << dec << "." << endl;
#endif
					wait_cnt++;
					if (wait_cnt%SATA_lane == 0)
						wait();
					if ((SATA_stop) && (SATA_buffer_DLLP_up_time != sc_time_stamp()))
						break;
				}
				if ((SATA_stop) && (SATA_buffer_DLLP_up_time != sc_time_stamp()))
				{
					SATA_stop = false;
					SATA_port.set_in_use(false);
					wait();
					continue;
				}
			}
			else
			{
				for (int i=0;i<3*4;i++)
				{
					SATA_port.TL_send_header_byte(SATA_buffer_DLL_TLP_down[SATA_buffer_DLL_TLP_down_out].TLP.header[i]);
#ifdef	DEBUG_SWITCH
					cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Send TLP Header to SATA Port : ";
					cout.width(2);
					cout.fill('0');
					cout << hex << (unsigned)SATA_buffer_DLL_TLP_down[SATA_buffer_DLL_TLP_down_out].TLP.header[i] << dec << "." << endl;
#endif
					wait_cnt++;
					if (wait_cnt%SATA_lane == 0)
						wait();
					if ((SATA_stop) && (SATA_buffer_DLLP_up_time != sc_time_stamp()))
						break;
				}
				if ((SATA_stop) && (SATA_buffer_DLLP_up_time != sc_time_stamp()))
				{
					SATA_stop = false;
					SATA_port.set_in_use(false);
					wait();
					continue;
				}
			}

			if (SATA_buffer_DLL_TLP_down[SATA_buffer_DLL_TLP_down_out].TLP.with_data)
			{
				if (SATA_buffer_DLL_TLP_down[SATA_buffer_DLL_TLP_down_out].TLP.length == 0)
				{
					for (int i=0;i<1024*PCIe_DOUBLE_WORD;i++)
					{
						switch (i%4)
						{
						case 0:
							SATA_port.TL_send_data_byte((byte)(SATA_buffer_DLL_TLP_down[SATA_buffer_DLL_TLP_down_out].TLP.data[i/4]>>24));
							break;
						case 1:
							SATA_port.TL_send_data_byte((byte)(SATA_buffer_DLL_TLP_down[SATA_buffer_DLL_TLP_down_out].TLP.data[i/4]>>16));
							break;
						case 2:
							SATA_port.TL_send_data_byte((byte)(SATA_buffer_DLL_TLP_down[SATA_buffer_DLL_TLP_down_out].TLP.data[i/4]>>8));
							break;
						case 3:
							SATA_port.TL_send_data_byte((byte)SATA_buffer_DLL_TLP_down[SATA_buffer_DLL_TLP_down_out].TLP.data[i/4]);
							break;
						}
#ifdef	DEBUG_SWITCH
						cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Send TLP Data to SATA Port : ";
						cout.width(2);
						cout.fill('0');
						switch (i%4)
						{
						case 0:
							cout << hex << ((SATA_buffer_DLL_TLP_down[SATA_buffer_DLL_TLP_down_out].TLP.data[i/4]>>24) & 0xFF) << dec << "." << endl;
							break;
						case 1:
							cout << hex << ((SATA_buffer_DLL_TLP_down[SATA_buffer_DLL_TLP_down_out].TLP.data[i/4]>>16) & 0xFF) << dec << "." << endl;
							break;
						case 2:
							cout << hex << ((SATA_buffer_DLL_TLP_down[SATA_buffer_DLL_TLP_down_out].TLP.data[i/4]>>8) & 0xFF) << dec << "." << endl;
							break;
						case 3:
							cout << hex << (SATA_buffer_DLL_TLP_down[SATA_buffer_DLL_TLP_down_out].TLP.data[i/4] & 0xFF) << dec << "." << endl;
							break;
						}
#endif
						wait_cnt++;
						if (wait_cnt%SATA_lane == 0)
							wait();
						if ((SATA_stop) && (SATA_buffer_DLLP_down_time != sc_time_stamp()))
							break;
					}
				}
				else
				{
					for (int i=0;i<SATA_buffer_DLL_TLP_down[SATA_buffer_DLL_TLP_down_out].TLP.length*4;i++)
					{
						switch (i%4)
						{
						case 0:
							SATA_port.TL_send_data_byte((byte)(SATA_buffer_DLL_TLP_down[SATA_buffer_DLL_TLP_down_out].TLP.data[i/4]>>24));
							break;
						case 1:
							SATA_port.TL_send_data_byte((byte)(SATA_buffer_DLL_TLP_down[SATA_buffer_DLL_TLP_down_out].TLP.data[i/4]>>16));
							break;
						case 2:
							SATA_port.TL_send_data_byte((byte)(SATA_buffer_DLL_TLP_down[SATA_buffer_DLL_TLP_down_out].TLP.data[i/4]>>8));
							break;
						case 3:
							SATA_port.TL_send_data_byte((byte)SATA_buffer_DLL_TLP_down[SATA_buffer_DLL_TLP_down_out].TLP.data[i/4]);
							break;
						}
#ifdef	DEBUG_SWITCH
						cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Send TLP Data to SATA Port : ";
						cout.width(2);
						cout.fill('0');
						switch (i%4)
						{
						case 0:
							cout << hex << ((SATA_buffer_DLL_TLP_down[SATA_buffer_DLL_TLP_down_out].TLP.data[i/4]>>24) & 0xFF) << dec << "." << endl;
							break;
						case 1:
							cout << hex << ((SATA_buffer_DLL_TLP_down[SATA_buffer_DLL_TLP_down_out].TLP.data[i/4]>>16) & 0xFF) << dec << "." << endl;
							break;
						case 2:
							cout << hex << ((SATA_buffer_DLL_TLP_down[SATA_buffer_DLL_TLP_down_out].TLP.data[i/4]>>8) & 0xFF) << dec << "." << endl;
							break;
						case 3:
							cout << hex << (SATA_buffer_DLL_TLP_down[SATA_buffer_DLL_TLP_down_out].TLP.data[i/4] & 0xFF) << dec << "." << endl;
							break;
						}
#endif
						wait_cnt++;
						if (wait_cnt%SATA_lane == 0)
							wait();
						if ((SATA_stop) && (SATA_buffer_DLLP_up_time != sc_time_stamp()))
							break;
					}
				}
				if ((SATA_stop) && (SATA_buffer_DLLP_up_time != sc_time_stamp()))
				{
					SATA_stop = false;
					SATA_port.set_in_use(false);
					wait();
					continue;
				}
			}

			if (SATA_buffer_DLL_TLP_down[SATA_buffer_DLL_TLP_down_out].TLP.TLP_digest)
			{
				for (int i=3;i>=0;i--)
				{
					SATA_port.TL_send_ECRC_byte(SATA_buffer_DLL_TLP_down[SATA_buffer_DLL_TLP_down_out].TLP.ECRC>>(8*i));
#ifdef	DEBUG_SWITCH
					cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Send TLP ECRC to SATA Port : ";
					cout.width(2);
					cout.fill('0');
					cout << hex << (unsigned)(SATA_buffer_DLL_TLP_down[SATA_buffer_DLL_TLP_down_out].TLP.ECRC>>(8*i)) << dec << "." << endl;
#endif
					wait_cnt++;
					if (wait_cnt%SATA_lane == 0)
						wait();
					if ((SATA_stop) && (SATA_buffer_DLLP_up_time != sc_time_stamp()))
						break;
				}
				if ((SATA_stop) && (SATA_buffer_DLLP_up_time != sc_time_stamp()))
				{
					SATA_stop = false;
					SATA_port.set_in_use(false);
					wait();
					continue;
				}
			}

			for (int i=3;i>=0;i--)
			{
				SATA_port.DLL_send_LCRC_byte(SATA_buffer_DLL_TLP_down[SATA_buffer_DLL_TLP_down_out].LCRC>>(8*i));
#ifdef	DEBUG_SWITCH
				cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Send LCRC to SATA Port : ";
				cout.width(2);
				cout.fill('0');
				cout << hex << (unsigned)(SATA_buffer_DLL_TLP_down[SATA_buffer_DLL_TLP_down_out].LCRC>>(8*i)) << dec << "." << endl;
#endif
				wait_cnt++;
				if (wait_cnt%SATA_lane == 0)
					wait();
				if ((SATA_stop) && (SATA_buffer_DLLP_up_time != sc_time_stamp()))
					break;
			}
			if ((SATA_stop) && (SATA_buffer_DLLP_up_time != sc_time_stamp()))
			{
				SATA_stop = false;
				SATA_port.set_in_use(false);
				wait();
				continue;
			}

			SATA_port.PL_send_symbol(END);
			SATA_port.set_in_use(false);
#ifdef	DEBUG_SWITCH
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Send END Symbol to SATA Port." << endl;
#endif
			SATA_buffer_DLL_TLP_down_out = (SATA_buffer_DLL_TLP_down_out+1)%MAX_BUFFER_SWITCH; 
			if (SATA_sequence_number > SATA_NAK_sequence_number)
				SATA_NAK_sequence_number++;
#ifdef	DEBUG_SWITCH
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "SEND DLL_TLP to SATA Port Complete!" << endl;
#endif
		}
		wait();
	}
}

void
PCIe_Switch::DMI_ack_nak_action()
{
	PCIe_DLLP dllp;

	while (true)
	{
		if ((DMI_buffer_DLL_TLP_down_in != DMI_buffer_DLL_TLP_down_out) && (DMI_buffer_DLL_TLP_down_time != sc_time_stamp()))
		{
			if (!DMI_is_NAK)
			{
				dllp = construct_DLLP_ACK_NAK(ACK, DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_out].sequence_number, 0);

				DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].with_data = DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_out].TLP.with_data;
				DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].DW4_header = DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_out].TLP.DW4_header;
				int limit;
				if (DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].DW4_header)
				{
					DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].header = new byte[PCIe_DOUBLE_WORD*4];
					limit = 16;
				}
				else
				{
					DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].header = new byte[PCIe_DOUBLE_WORD*3];
					limit = 12;
				}
				for (int i=0;i<limit;i++)
					DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].header[i] = DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_out].TLP.header[i];
				DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].length = DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_out].TLP.length;
				if (DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].with_data)
				{
					if (DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].length == 0)
					{
						DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].data = new unsigned[1024];
						for (int i=0;i<1024;i++)
							DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].data[i] = DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_out].TLP.data[i];
					}
					else
					{
						DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].data = new unsigned[DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].length];
						for (int i=0;i<DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].length;i++)
							DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].data[i] = DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_out].TLP.data[i];
					}
				}
				DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].TLP_digest = DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_out].TLP.TLP_digest;
				DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].ECRC = DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_out].TLP.ECRC;

				DMI_buffer_TLP_down_in = (DMI_buffer_TLP_down_in+1)%MAX_BUFFER_SWITCH;
				DMI_buffer_TLP_down_time = sc_time_stamp();
			}
			else
			{
				dllp = construct_DLLP_ACK_NAK(NAK, DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_out].sequence_number, 0);
			}
			delete[] DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_out].TLP.header;
			if (DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_out].TLP.with_data)
				delete[] DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_out].TLP.data;
			DMI_buffer_DLL_TLP_down_out = (DMI_buffer_DLL_TLP_down_out+1)%MAX_BUFFER_SWITCH;

#ifdef	DEBUG_SWITCH
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "DMI ack_nak DLLP Type : ";
			cout.width(2);
			cout.fill('0');
			cout << hex << (unsigned)dllp.type << dec << endl;
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "DMI ack_nak DLLP Data : ";
			for (int i=0; i<3; i++)
			{
				cout.width(2);
				cout.fill('0');
				cout << hex << (unsigned)dllp.data[i] << dec << " ";
			}
			cout << endl;
#endif
			DMI_buffer_DLLP_up[DMI_buffer_DLLP_up_in] = dllp;
			DMI_buffer_DLLP_up_in = (DMI_buffer_DLLP_up_in+1)%MAX_BUFFER_SWITCH;
			DMI_buffer_DLLP_up_time = sc_time_stamp();
		}
		wait();
	}
}

void
PCIe_Switch::DMI_DLLP_send_action()
{
	unsigned wait_cnt;

	DMI_lane = DMI_port.lane_width();

	while (true)
	{
		wait_cnt = 0;
		if ((DMI_buffer_DLLP_up_in != DMI_buffer_DLLP_up_out) &&
			(!DMI_port.is_in_use()) &&
			(DMI_port.check_release_time() != sc_time_stamp()) &&
			((DMI_buffer_DLLP_up_time != sc_time_stamp()) || (DMI_buffer_DLLP_up_in != (DMI_buffer_DLLP_up_out+1)%MAX_BUFFER_SWITCH)) &&
			(arbitrate_port(DMI_port.get_id(),0)))
		{
			DMI_port.set_in_use(true);
			DMI_port.PL_send_symbol(SDP);
#ifdef	DEBUG_SWITCH
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Send SDP Symbol to DMI Port." << endl;
#endif
			wait_cnt++;
			if (wait_cnt%DMI_lane == 0)
				wait();

			DMI_port.DLL_send_type_byte((byte)DMI_buffer_DLLP_up[DMI_buffer_DLLP_up_out].type);
#ifdef	DEBUG_SWITCH
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Send DLLP Type to DMI Port : ";
			cout.width(2);
			cout.fill('0');
			cout << hex << (unsigned)DMI_buffer_DLLP_up[DMI_buffer_DLLP_up_out].type << dec << "." << endl;
#endif
			wait_cnt++;
			if (wait_cnt%DMI_lane == 0)
				wait();

			for (int i=0; i<3; i++)
			{
				DMI_port.DLL_send_data_byte(DMI_buffer_DLLP_up[DMI_buffer_DLLP_up_out].data[i]);
#ifdef	DEBUG_SWITCH
				cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Send DLLP Data to DMI Port : ";
				cout.width(2);
				cout.fill('0');
				cout << hex << (unsigned)DMI_buffer_DLLP_up[DMI_buffer_DLLP_up_out].data[i] << dec << "." << endl;
#endif
				wait_cnt++;
				if (wait_cnt%DMI_lane == 0)
					wait();
			}
			for (int i=1; i>=0; i--)
			{
				DMI_port.DLL_send_CRC_byte(DMI_buffer_DLLP_up[DMI_buffer_DLLP_up_out].CRC>>8*i);
#ifdef	DEBUG_SWITCH
				cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Send CRC to DMI Port : ";
				cout.width(2);
				cout.fill('0');
				cout << hex << (unsigned)(DMI_buffer_DLLP_up[DMI_buffer_DLLP_up_out].CRC>>8*i) << dec << "." << endl;
#endif
				wait_cnt++;
				if (wait_cnt%DMI_lane == 0)
					wait();
			}

			DMI_port.PL_send_symbol(END);
			DMI_port.set_in_use(false);
#ifdef	DEBUG_SWITCH
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Send END Symbol to DMI Port." << endl;
#endif
			DMI_buffer_DLLP_up_out = (DMI_buffer_DLLP_up_out+1)%MAX_BUFFER_SWITCH;
#ifdef	DEBUG_SWITCH
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "SEND DLLP to DMI Port Complete!" << endl;
#endif
		}
		wait();
	}
}

void
PCIe_Switch::SATA_ack_nak_action()
{
	PCIe_DLLP dllp;

	while (true)
	{
		if ((SATA_buffer_DLL_TLP_up_in != SATA_buffer_DLL_TLP_up_out) && (SATA_buffer_DLL_TLP_up_time != sc_time_stamp()))
		{
			if (!SATA_is_NAK)
			{
				dllp = construct_DLLP_ACK_NAK(ACK, SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_out].sequence_number, 0);

				SATA_buffer_TLP_up[SATA_buffer_TLP_up_in].with_data = SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_out].TLP.with_data;
				SATA_buffer_TLP_up[SATA_buffer_TLP_up_in].DW4_header = SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_out].TLP.DW4_header;
				int limit;
				if (SATA_buffer_TLP_up[SATA_buffer_TLP_up_in].DW4_header)
				{
					SATA_buffer_TLP_up[SATA_buffer_TLP_up_in].header = new byte[PCIe_DOUBLE_WORD*4];
					limit = 16;
				}
				else
				{
					SATA_buffer_TLP_up[SATA_buffer_TLP_up_in].header = new byte[PCIe_DOUBLE_WORD*3];
					limit = 12;
				}
				for (int i=0;i<limit;i++)
					SATA_buffer_TLP_up[SATA_buffer_TLP_up_in].header[i] = SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_out].TLP.header[i];
				SATA_buffer_TLP_up[SATA_buffer_TLP_up_in].length = SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_out].TLP.length;
				if (SATA_buffer_TLP_up[SATA_buffer_TLP_up_in].with_data)
				{
					if (SATA_buffer_TLP_up[SATA_buffer_TLP_up_in].length == 0)
					{
						SATA_buffer_TLP_up[SATA_buffer_TLP_up_in].data = new unsigned[1024];
						for (int i=0;i<1024;i++)
							SATA_buffer_TLP_up[SATA_buffer_TLP_up_in].data[i] = SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_out].TLP.data[i];
					}
					else
					{
						SATA_buffer_TLP_up[SATA_buffer_TLP_up_in].data = new unsigned[SATA_buffer_TLP_up[SATA_buffer_TLP_up_in].length];
						for (int i=0;i<SATA_buffer_TLP_up[SATA_buffer_TLP_up_in].length;i++)
							SATA_buffer_TLP_up[SATA_buffer_TLP_up_in].data[i] = SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_out].TLP.data[i];
					}
				}
				SATA_buffer_TLP_up[SATA_buffer_TLP_up_in].TLP_digest = SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_out].TLP.TLP_digest;
				SATA_buffer_TLP_up[SATA_buffer_TLP_up_in].ECRC = SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_out].TLP.ECRC;

				SATA_buffer_TLP_up_in = (SATA_buffer_TLP_up_in+1)%MAX_BUFFER_SWITCH;
				SATA_buffer_TLP_up_time = sc_time_stamp();
			}
			else
			{
				dllp = construct_DLLP_ACK_NAK(NAK, SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_out].sequence_number, 0);
			}
			delete[] SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_out].TLP.header;
			if (SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_out].TLP.with_data)
				delete[] SATA_buffer_DLL_TLP_up[SATA_buffer_DLL_TLP_up_out].TLP.data;
			SATA_buffer_DLL_TLP_up_out = (SATA_buffer_DLL_TLP_up_out+1)%MAX_BUFFER_SWITCH;

#ifdef	DEBUG_SWITCH
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "SATA ack_nak DLLP Type : ";
			cout.width(2);
			cout.fill('0');
			cout << hex << (unsigned)dllp.type << dec << endl;
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "SATA ack_nak DLLP Data : ";
			for (int i=0; i<3; i++)
			{
				cout.width(2);
				cout.fill('0');
				cout << hex << (unsigned)dllp.data[i] << dec << " ";
			}
			cout << endl;
#endif
			SATA_buffer_DLLP_down[SATA_buffer_DLLP_down_in] = dllp;
			SATA_buffer_DLLP_down_in = (SATA_buffer_DLLP_down_in+1)%MAX_BUFFER_SWITCH;
			SATA_buffer_DLLP_down_time = sc_time_stamp();
		}
		wait();
	}
}

void
PCIe_Switch::SATA_DLLP_send_action()
{
	unsigned wait_cnt;

	SATA_lane = SATA_port.lane_width();

	while (true)
	{
		wait_cnt = 0;
		if ((SATA_buffer_DLLP_down_in != SATA_buffer_DLLP_down_out) &&
			(!SATA_port.is_in_use()) &&
			(SATA_port.check_release_time() != sc_time_stamp()) &&
			((SATA_buffer_DLLP_down_time != sc_time_stamp()) || (SATA_buffer_DLLP_down_in != (SATA_buffer_DLLP_down_out+1)%MAX_BUFFER_SWITCH)) &&
			(arbitrate_port(SATA_port.get_id(),0)))
		{
			SATA_port.set_in_use(true);
			SATA_port.PL_send_symbol(SDP);
#ifdef	DEBUG_SWITCH
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Send SDP Symbol to SATA Port." << endl;
#endif
			wait_cnt++;
			if (wait_cnt%SATA_lane == 0)
				wait();

			SATA_port.DLL_send_type_byte((byte)SATA_buffer_DLLP_down[SATA_buffer_DLLP_down_out].type);
#ifdef	DEBUG_SWITCH
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Send DLLP Type to SATA Port : ";
			cout.width(2);
			cout.fill('0');
			cout << hex << (unsigned)SATA_buffer_DLLP_down[SATA_buffer_DLLP_down_out].type << dec << "." << endl;
#endif
			wait_cnt++;
			if (wait_cnt%SATA_lane == 0)
				wait();

			for (int i=0; i<3; i++)
			{
				SATA_port.DLL_send_data_byte(SATA_buffer_DLLP_down[SATA_buffer_DLLP_down_out].data[i]);
#ifdef	DEBUG_SWITCH
				cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Send DLLP Data to SATA Port : ";
				cout.width(2);
				cout.fill('0');
				cout << hex << (unsigned)SATA_buffer_DLLP_down[SATA_buffer_DLLP_down_out].data[i] << dec << "." << endl;
#endif
				wait_cnt++;
				if (wait_cnt%SATA_lane == 0)
					wait();
			}
			for (int i=1; i>=0; i--)
			{
				SATA_port.DLL_send_CRC_byte(SATA_buffer_DLLP_down[SATA_buffer_DLLP_down_out].CRC>>8*i);
#ifdef	DEBUG_SWITCH
				cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Send CRC to SATA Port : ";
				cout.width(2);
				cout.fill('0');
				cout << hex << (unsigned)(SATA_buffer_DLLP_down[SATA_buffer_DLLP_down_out].CRC>>8*i) << dec << "." << endl;
#endif
				wait_cnt++;
				if (wait_cnt%SATA_lane == 0)
					wait();
			}

			SATA_port.PL_send_symbol(END);
			SATA_port.set_in_use(false);
#ifdef	DEBUG_SWITCH
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Send END Symbol to SATA Port." << endl;
#endif
			SATA_buffer_DLLP_down_out = (SATA_buffer_DLLP_down_out+1)%MAX_BUFFER_SWITCH;
#ifdef	DEBUG_SWITCH
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "SEND DLLP to SATA Port Complete!" << endl;
#endif
		}
		wait();
	}
}